﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using SQLToolbox.Types;


namespace SQLToolbox.Types
{



	public class SchemaObjectComparison
	{
		public string Name { get; set; }
		public string LeftText { get; set; }
		public string RightText { get; set; }

		public ComparisonStatus Status { get; set; }
		public SchemaUpdateAction LeftToRightAction
		{
			get
			{
				switch (Status)
				{
					case ComparisonStatus.Equal:
						return SchemaUpdateAction.Skip;
					case ComparisonStatus.Different:
						return SchemaUpdateAction.Alter;
					case ComparisonStatus.New:
						return SchemaUpdateAction.Create;
					case ComparisonStatus.Missing:
						return SchemaUpdateAction.Drop;
					default:
						return SchemaUpdateAction.Skip;
				}

			}
		}
		public SchemaUpdateAction RightToLeftAction
		{
			get
			{
				switch (Status)
				{
					case ComparisonStatus.Equal:
						return SchemaUpdateAction.Skip;
					case ComparisonStatus.Different:
						return SchemaUpdateAction.Alter;
					case ComparisonStatus.New:
						return SchemaUpdateAction.Drop;
					case ComparisonStatus.Missing:
						return SchemaUpdateAction.Create;
					default:
						return SchemaUpdateAction.Skip;
				}
			}
		}
		public SchemaObjectType Type { get; set; }
		public SchemaObject LeftObject { get; set; }
		public SchemaObject RightObject { get; set; }

		public ScriptComparisonResult ScriptComparisonResult { get; set; }
		List<SchemaObjectComparison> children = new List<SchemaObjectComparison>();

		public IEnumerable<SchemaObjectComparison> Children
		{
			get { return children; }
		}

		public void AddChild(SchemaObjectComparison child)
		{
			children.Add(child);
		}
	}

	/// <summary>
	/// Type of database object to compare
	/// </summary>
	public enum SchemaObjectType
	{
		/// <summary>
		/// Not applicaple, the object type is not supported by SQLToolbox
		/// </summary>
		NotApplicable,
		/// <summary>
		/// Database Table
		/// </summary>
		Table,
		/// <summary>
		/// Database View
		/// </summary>
		View,
		/// <summary>
		/// Database Stored procedure
		/// </summary>
		Procedure,
		/// <summary>
		/// User Defined Type 
		/// </summary>
		UserDefinedType,
		/// <summary>
		/// User Defined data type
		/// </summary>
		UserDefinedDataType,
		/// <summary>
		/// User Defined function
		/// </summary>
		UserDefinedFunction,
		/// <summary>
		/// Login
		/// </summary>
		Login,
		/// <summary>
		/// 
		/// </summary>
		Trigger,
		/// <summary>
		/// 
		/// </summary>
		Index,
		/// <summary>
		/// 
		/// </summary>
		ForeignKey,
		/// <summary>
		/// 
		/// </summary>
		Statistic

	}

	public static class SchemaObjectTypeExtender
	{
		public static string ToSQLString(this SchemaObjectType sot)
		{
			switch (sot)
			{
				case SchemaObjectType.Table:
					return "TABLE";
				case SchemaObjectType.View:
					return "VIEW";
				case SchemaObjectType.Procedure:
					return "PROCEDURE";
				case SchemaObjectType.UserDefinedType:
					return "TYPE";
				case SchemaObjectType.UserDefinedDataType:
					return "TYPE";
				case SchemaObjectType.UserDefinedFunction:
					return "FUNCTION";
				case SchemaObjectType.Login:
					return "LOGIN";
				case SchemaObjectType.Trigger:
					return "TRIGGER"; ;
				case SchemaObjectType.Index:
					return "INDEX"; ;
				case SchemaObjectType.ForeignKey:
					return "CONSTRAINT"; ;
				case SchemaObjectType.Statistic:
					return "STATISTIC"; ;
				case SchemaObjectType.NotApplicable:
				default:
					return string.Empty;
			}
		}
	}
	/// <summary>
	/// Action needed for making the objects the same
	/// </summary>
	public enum SchemaUpdateAction
	{

		/// <summary>
		/// The source side is defferent from the tardet side
		/// </summary>
		Alter,
		/// <summary>
		/// The object exists only on source side
		/// </summary>
		Create,
		/// <summary>
		/// The object exists only on target side
		/// </summary>
		Drop,
		/// <summary>
		/// Skip - the objects are equal no action needed
		/// </summary>
		Skip
	}

	/// <summary>
	/// Direction of the update action
	/// </summary>
	public enum UpdateDirection
	{
		/// <summary>
		/// Left-to-Right
		/// </summary>
		LeftToRight,
		/// <summary>
		/// Right-to-Left
		/// </summary>
		RightToLeft
	}


	public enum ComparisonStatus
	{
		/// <summary>
		/// Sides are equal
		/// </summary>
		Equal,
		/// <summary>
		/// Sides are different
		/// </summary>
		Different,
		/// <summary>
		/// The object exists only on source side
		/// </summary>
		New,
		/// <summary>
		/// The object exists only on target side
		/// </summary>
		Missing
	}

	public class SchemaComaprison : IEnumerable<SchemaObjectComparison>, ICollection<SchemaObjectComparison>, IList<SchemaObjectComparison>
		, INotifyCollectionChanged
	{
		public DBConnectionProperties Left { get; set; }
		public DBConnectionProperties Right { get; set; }

		private List<SchemaObjectComparison> list = new List<SchemaObjectComparison>();


		#region IEnumerable<SchemaObjectComparison> Members

		public IEnumerator<SchemaObjectComparison> GetEnumerator()
		{
			return list.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return list.GetEnumerator();
		}

		#endregion

		#region ICollection<SchemaObjectComparison> Members

		public void Add(SchemaObjectComparison item)
		{
			list.Add(item);
			if (CollectionChanged != null)
				CollectionChanged(this,
					new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));

		}

		public void Clear()
		{
			list.Clear();
			if (CollectionChanged != null)
				CollectionChanged(this,
					new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

		}

		public bool Contains(SchemaObjectComparison item)
		{
			return list.Contains(item);
		}

		public void CopyTo(SchemaObjectComparison[] array, int arrayIndex)
		{
			list.ToArray().CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return list.Count; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public bool Remove(SchemaObjectComparison item)
		{
			bool ret = list.Remove(item);
			if (CollectionChanged != null)
				CollectionChanged(this,
					new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
			return ret;

		}

		#endregion


		#region IList<SchemaObjectComparison> Members

		public void Insert(int index, SchemaObjectComparison item)
		{
			list.Insert(index, item);
			if (CollectionChanged != null)
				CollectionChanged(this,
					new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));

		}

		public int IndexOf(SchemaObjectComparison item)
		{
			return list.IndexOf(item);
		}

		public void RemoveAt(int index)
		{
			var item = list[index];
			list.RemoveAt(index);
			if (CollectionChanged != null)
				CollectionChanged(this,
					new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));

		}

		public SchemaObjectComparison this[int index]
		{
			get
			{
				return list[index];
			}
			set
			{
				var item = list[index];
				list[index] = value;
				if (CollectionChanged != null)
					CollectionChanged(this,
						new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, item, index));

			}
		}


		#endregion

		#region INotifyCollectionChanged Members

		public event NotifyCollectionChangedEventHandler CollectionChanged;

		#endregion


	}
}
